PySockInit(user, pass, sheet) {
    Global
    if (pysocket_init_cmpl) {
        Process, Exist, %Py_Spr_PID%
        if (ErrorLevel) {
            return 0
        } else {
            dout("Error py socket, revoke.")
            SendData(MainSocket, "py_exit")
            NormalClose()
        }
    }

    OnExit, ExitSub

    py_hide_opt = Hide ; for Release version
    py_hide_opt =  ; for Debug version
    py_run_opt = /c

    cmd = % ComSpec " " py_run_opt " python append_gSpreadSheet.py"
    Run, % cmd, ,%py_hide_opt% , Py_Spr_PID
    if (ErrorLevel) {
        MsgBox Error invoke py sock.
        return -1
    }

    Sleep, 1000
    dout("Py PID:: " Py_Spr_PID)

    NetworkAddress = 127.0.0.1 ;Listen address, 0.0.0.0 = any
    NetworkPort	= 50007	;Listen port

    MaxDataLength  = 4096	;Longest message that can be recieved.

    MainSocket := PrepareSocket(NetworkAddress, NetworkPort)
    If (MainSocket = -1) {
        Msgbox PySockInit: PrepareSocket Error!
        return 1
    }

    DetectHiddenWindows On
    Process Exist
    MainWindow := WinExist("ahk_class AutoHotkey ahk_pid " . ErrorLevel)
    DetectHiddenWindows Off

    ; FD_READ + FD_CLOSE + FD_ACCEPT = 41
    If DllCall("Ws2_32\WSAAsyncSelect", "UInt", MainSocket, "UInt", MainWindow, "UInt", 5588, "Int", 41)
    {
        MsgBox % "WSAAsyncSelect() indicated Winsock error " . DllCall("Ws2_32\WSAGetLastError")
        return 1
    }
    if (!pysocket_init_cmpl) {
        OnMessage(5588, "ReceiveData", 99) ;Allow 99 (i.e. lots of) threads.
    }

    SendData(MainSocket, "do_login " user " " pass "|")
    SendData(MainSocket, "open_sheet " sheet "|")
    pysocket_init_cmpl := True
    return 0
}

; ----------------------------------------
; Imported Winsock Functions start
; ----------------------------------------
PrepareSocket(IPAddress, Port) {
    VarSetCapacity(wsaData, 32)
    Result := DllCall("Ws2_32\WSAStartup", "UShort", 0x0002, "UInt", &wsaData)
    If ErrorLevel
    {
        MsgBox WSAStartup() could not be called due to error %ErrorLevel%. Winsock 2.0 or higher is required.
        return -1
    }
    If Result  ; Non-zero, which means it failed (most Winsock functions return 0 upon success).
    {
        MsgBox % "WSAStartup() indicated Winsock error " . DllCall("Ws2_32\WSAGetLastError")
        return -1
    }

    ;AF_INET = 2   SOCK_STREAM = 1   IPPROTO_TCP = 6
    Socket := DllCall("Ws2_32\socket", "Int", 2, "Int", 1, "Int", 6)
    If (Socket = -1)
    {
        MsgBox % "Socket() indicated Winsock error " . DllCall("Ws2_32\WSAGetLastError")
        return -1
    }

    VarSetCapacity(SocketAddress, 16)
    InsertInteger2(2, SocketAddress, 0, 2) ; AF_INET = 2
    InsertInteger2(DllCall("Ws2_32\htons", "UShort", Port), SocketAddress, 2, 2)   ; sin_port
    InsertInteger2(DllCall("Ws2_32\inet_addr", "AStr", IPAddress), SocketAddress, 4, 4)   ; sin_addr.s_addr

    If DllCall("Ws2_32\connect", "UInt", Socket, "UInt", &SocketAddress, "Int", 16)
    {
        Result := DllCall("Ws2_32\WSAGetLastError")
        If (Result = 10061) 
        {
            DBGOUT("Connection Refused. That probably means the server script is not running.")
            Sleep, 1000
            Reload
        }
        Else
        {
            MsgBox % "Connect() indicated Winsock error " . Result
        }
        conn_fail := 1
    } else {
        conn_fail := 0
    }

    return Socket
}

AppendSocket(skt_received) {
    Global

    Loop, %scnt%
    {
        DBGOUT("chk(" A_Index . "):" . skt_%A_Index%)
        if (skt_%A_Index% > 0) {
            ; is in use.
            if (skt_%A_Index% = skt_received) {
                IndivisualClose(skt_received)
                skt_%A_Index% := skt_received
                DBGOUT("Connected=" . A_Index . " ackskt=" . skt_received)
                return A_Index
            }
        } else {
            ; seems empty.
            skt_%A_Index% := skt_received
            scnt := scnt + 1
            DBGOUT("now scnt=" . scnt)
            return A_Index
        }
    }
    return 0
}

ReceiveData(wParam, lParam) {
    Global MaxDataLength, OutgoingSocket, CommandList, RunningCommands, ClientResponse

    skt_rcv := wParam

    Event := lParam & 0xFFFF

    DBGOUT("ReceiveData")
    If (Event = 8) ; FD_ACCEPT = 8
    {
        skt_accepted := DllCall("Ws2_32\accept", "UInt", wParam, "UInt", &SocketAddress, "Int", 0)
        If (skt_accepted < 0) {
            MsgBox % "Accept() indicated Winsock error " . DllCall("Ws2_32\WSAGetLastError")
        } Else {
            AppendSocket(skt_accepted)
        }
        return 1
    }

    VarSetCapacity(ReceivedData, MaxDataLength, 0)
    ReceivedDataLength := DllCall("Ws2_32\recv", "UInt", wParam, "WStr", ReceivedData, "Int", MaxDataLength, "Int", 0)
    If (ReceivedDataLength = 0) { ; The connection was gracefully closed
        DBGOUT("The connection was gracefully closed(len0)")
        return IndivisualClose(skt_rcv)
    }

    if (ReceivedDataLength == -1) {
        DBGOUT("Attempt to close skt:" . skt_rcv)
        WinsockError := DllCall("Ws2_32\WSAGetLastError")
        If (WinsockError = 10035) { ; No more data to be read
            DBGOUT("Close cause 10035")
            return 1
        }
        If (WinsockError = 10054) { ; Connection closed
            DBGOUT("Close cause 10054")
            return IndivisualClose(skt_rcv)
        }
        MsgBox % "Recv() indicated Winsock error " . WinsockError
    }

   DBGOUT("Got:" ReceivedData ":")
   return 1
}

; Close All Sockets
NormalClose() {
    Global
    Local Result

    Loop, %scnt%
    {
        if (skt_%A_Index% > 0) {
            Result := DllCall("Ws2_32\closesocket", "UInt", skt_%A_Index%)
            If (Result != 0)
            {
                MsgBox % "CloseSocket() indicated Winsock error " . DllCall("Ws2_32\WSAGetLastError")
                ExitApp
            }
        }
        skt_%A_Index% = 
        CharType_%A_Index% = 
    }
    return 1
}

; Added. Close the specified Socket
IndivisualClose(close_socket) {
    Global
    Local Result

    DBGOUT("iclose:" . close_socket)
    Loop, %scnt%
    {
        if (skt_%A_Index% = close_socket) {
            DBGOUT("Closing socket: " . close_socket . "(" . A_Index . ")" )
            Result := DllCall("Ws2_32\closesocket", "UInt", skt_%A_Index%)
            If (Result != 0)
            {
                MsgBox % "CloseSocket() indicated Winsock error " . DllCall("Ws2_32\WSAGetLastError")
                ExitApp
            }
            ; Initialize
            skt_%A_Index% := 0
            CharType_%A_Index% = 
        }
    }
    ; Menu TRAY, Tip, AHK Remote Server`n%A_IPAddress1%
    return 1
}

SendData(Socket, Data) {
    global IsSendDataEnable
    if (IsSendDataEnable = 0) {
        DBGOUT("abort")
        return
    }
;   DBGOUT("SendData:" Data)
    SendRet := DllCall("Ws2_32\send", "UInt", Socket, "WStr", Data, "Int", StrLen(Data)*2, "Int", 0)
    If (SendRet = -1) {
        DBGOUT("Send() indicated Winsock error:")
        DBGOUT(DllCall("Ws2_32\WSAGetLastError"))
        Sleep, 3000
    }
    return SendRet
}

;By Laszlo, used by the password function.
RC4txt2hex(Data,Pass) { 
    Format := A_FormatInteger
    SetFormat Integer, Hex
    b := 0, j := 0 
    VarSetCapacity(Result,StrLen(Data)*4) 
    Loop 256 {
        a := A_Index - 1 
        Key%a% := Asc(SubStr(Pass, Mod(a,StrLen(Pass))+1, 1)) 
        sBox%a% := a 
    } 
    Loop 256 { 
        a := A_Index - 1 
        b := b + sBox%a% + Key%a%  & 255 
        T := sBox%a% 
        sBox%a% := sBox%b% 
        sBox%b% := T 
   } 
   Loop Parse, Data 
   { 
        i := A_Index & 255 
        j := sBox%i% + j  & 255 
        k := sBox%i% + sBox%j%  & 255 
        Result .= Asc(A_LoopField)^sBox%k% 
   } 
   Result := RegExReplace(Result, "0x(.)(?=0x|$)", "0$1") 
   StringReplace Result, Result, 0x,,All 
   SetFormat Integer, %Format% 
   return Result 
}

InsertInteger2(pInteger, ByRef pDest, pOffset = 0, pSize = 4) {
    Loop %pSize%  ; Copy each byte in the integer into the structure as raw binary data.
        DllCall("RtlFillMemory", "UInt", &pDest + pOffset + A_Index-1, "UInt", 1, "UChar", pInteger >> 8*(A_Index-1) & 0xFF)
}

DBGOUT(dstr) {
    Global pktcnt
    return

    if (pktcnt=) {
        pktcnt = 0
    }
    pktcnt++
    OutputDebug % "[" pktcnt "] " dstr
}
